/*   The MIT License
 *   
 *   Carina Engine
 *   Copyright (c) 2009 2010 2011 2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#ifndef DEBUGGUI_HH_
#define DEBUGGUI_HH_

#include "carina/renderer-base.hh"

#include "carina/resources.hh"
#include "carina/common/patterns.hh"
#include "carina/common/timer.hh"

#include "carina/common/global.hh"

namespace Carina
{
namespace GUI
{
class Font;
typedef shared_ptr<Font> FontPtr;

class CharRenderer: public non_copyable
{
    RendererPtr                 m_Renderer;

    ShaderProgramPtr            m_Prog;
    StateObjectPtr              m_State;
    BlendStateObjectPtr         m_BlendState;
    DepthStencilStateObjectPtr  m_DepthStencilState;
    InputLayoutPtr              m_Layout;

    FontPtr                     m_Font;

    UniformVarPtr               u_TransformMatrix;
    UniformVarPtr               u_Color;
    TextureVarPtr               u_Texture;
public:
    CharRenderer(ResourceManager& res_mgr);

    RendererPtr getRenderer() { return m_Renderer; }

    void setup(const FontPtr& font, ScopedState& state, ScopedBlendState& blend_state, ScopedDepthStencilState& depth_stencil);

    void renderChar(unsigned ch, Matrix4& mat);

    Matrix4 getProjectMatrix() const;
    void setTransformMatrix(const Matrix4& mat) { u_TransformMatrix->set(mat); }
    void setColor(const Vector3& vec) { u_Color->set(vec); }
};

class Font: public non_copyable
{
    size_t          m_FontHeight;
    TexturePtr      m_FontTexture;

    VideoBufferPtr  m_VBO;

    float           m_CharAdvance[128];

public:
    Font(const RendererPtr& renderer, const string& filename);
    ~Font();

    VideoBufferPtr getVBO() { return m_VBO; }
    TexturePtr getTexture() { return m_FontTexture; }

    float getCharAdvance(size_t idx) const
    {
#ifndef CARINA_UNSAFE
        if(idx >= CE_FIXED_ARRAY_SIZE(m_CharAdvance))
            THROW_EXCEPTION("Bad character index");
#endif
        return m_CharAdvance[idx];
    }

    void setup();
};

typedef shared_ptr<CharRenderer> CharRendererPtr;

class System: public Singleton<System>
{
    typedef std::unordered_map<string, FontPtr> FontMap;
    FontMap m_FontMap;

    ResourceManager &m_ResMgr;

    FontPtr             m_DefaultFont;
    CharRendererPtr     m_Renderer;
public:
    System(ResourceManager& rmgr);
    ~System() {}

    static FontPtr getFont(const string& str);

    static FontPtr getDefaultFont() { return GUI::System::getSingleton().m_DefaultFont; }
    static CharRendererPtr getDefaultCharRenderer() { return GUI::System::getSingleton().m_Renderer; }
};

class Label
{
    FontPtr         m_Font;
    CharRendererPtr m_CharRenderer;

    string          m_Text;
    Vector3         m_Color;
    Vector2         m_Position;
public:
    Label();
    Label(const string& text);
    ~Label() {}

    void setText(const string& str) { m_Text = str; }
    string getText() { return m_Text; }

    void setRenderer(const CharRendererPtr& crnd) { m_CharRenderer = crnd; }
    void setFont(const FontPtr& fnt) { m_Font = fnt; }
    void setFont(const string& fontname) { m_Font = GUI::System::getFont(fontname); }
    void setPosition(const Vector2& pos) { m_Position = pos; }

    void render();
};
}

class FPSCounter
{
    GUI::Label  m_FPSText;

    nanosec next_frame;
    size_t  count_FPS,
            FPS;
public:
    FPSCounter();
    ~FPSCounter();

    void update(nanosec time);
};
}

#endif /* DEBUGGUI_HH_ */
